home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $RCSfile: CheckDisk.c,v $
- ** $Filename: CheckDisk.c $
- ** $Revision: 0.1 $
- ** $Date: 1997/04/12 17:33:51 $
- **
- ** Check a disk device for hard errors (version 0.7)
- **
- ** (C) Copyright 1997-2002 by Etienne Vogt
- */
-
- #include <exec/alerts.h>
- #include <exec/memory.h>
- #include <exec/io.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/dosasl.h>
- #include <dos/dostags.h>
- #include <dos/filehandler.h>
- #include <workbench/startup.h>
- #include <devices/newstyle.h>
- #include <devices/trackdisk.h>
- #include <libraries/multiuser.h>
- #define __USE_SYSBASE
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/multiuser.h>
- #include <clib/alib_protos.h>
- #include <string.h>
- #include "ffs.h"
-
- struct DiskDevice mydiskdev;
-
- #define BBL_SIZE 64 /* Number of bad blocks in one table */
-
- struct BadBlockList
- { struct BadBlockList *bbl_Link; /* Pointer to next structure */
- ULONG bbl_BadBlocks[BBL_SIZE]; /* Key IDs of bad blocks */
- };
-
- #define ID_MUFS_DISK 0x6d754653 /* DosType for multiuser filesystem */
-
- #define FIBB_HOLD 7 /* h protection bit (hold/hidden) */
- #define FIBF_HOLD (1L << FIBB_HOLD)
-
- #define DDFB_READWRITE 31 /* non-destructive write test */
- #define DDFB_MODIFIED 30 /* Bad block mappings have changed */
-
- #define DDFF_READWRITE (1L << DDFB_READWRITE)
- #define DDFF_MODIFIED (1L << DDFB_MODIFIED)
-
- #define NUMBBNAMES 3
-
- static STRPTR BadBlockFileNames[] = { "BadBlocks.sys", "[secteurs.hs]", "bad.blocks" };
-
- struct ExecBase *SysBase;
- struct DosLibrary *DOSBase;
- struct muBase *muBase;
- struct MsgPort *DeviceMP;
- struct IOStdReq *DeviceIO;
- static struct WBStartup *wbmsg;
- static struct RDArgs *myrda;
- static struct BadBlockList *BBList;
- static ULONG *bitmap, *rootblock;
-
- static UBYTE version[] = "$VER: CheckDisk 0.7 (4.8.2002)";
- static UBYTE template[] = "DEVICE/A,NOINHIBIT/S,RW=READWRITE/S,S=SEVERE/S,RESET/S,LO=LOWCYL/K/N,HI=HIGHCYL/K/N,V=VERBOSE/S,BUFCYL/K/N";
-
- #define OPT_DEVICE 0
- #define OPT_NOINHIBIT 1
- #define OPT_READWRITE 2
- #define OPT_SEVERE 3
- #define OPT_RESET 4
- #define OPT_LOWCYL 5
- #define OPT_HIGHCYL 6
- #define OPT_VERBOSE 7
- #define OPT_BUFCYL 8
- #define OPTMAX 9
-
- ULONG __saveds main(void);
- static void cleanexit(ULONG rc);
- static int checkdisk(void);
- static int checkcyl(struct IOStdReq *ioreq, APTR buffer, ULONG bufsize, int cyl);
- static int checkbysectors(struct IOStdReq *ioreq, APTR buffer, ULONG size, int cyl, int starthead);
- static BPTR openbadblocksfile(STRPTR device);
- static struct BadBlockList *readbadblocks(BPTR bbflock);
- static int writebadblocks(struct BadBlockList *bbl, BPTR bbflock);
- static void freebadblocklist(struct BadBlockList *bbl);
- static BOOL checkbadblock(ULONG KeyID);
- static void mapbadblock(ULONG badcyl, ULONG badhead, ULONG badsector);
- static BOOL addbadblock(ULONG KeyID);
- static ULONG getfreeblock(ULONG *bitmap);
- static void freebadblocks(struct BadBlockList *bbl);
- static __inline BOOL checkprotection(struct IOStdReq *ioreq);
- static __inline BOOL checkstate(struct IOStdReq *ioreq);
-
- ULONG __saveds main(void) /* No startup code */
- { struct Process *myproc;
- LONG opts[OPTMAX];
- ULONG rc = 0;
-
- SysBase = *(struct ExecBase **)4;
- DOSBase = NULL;
- wbmsg = NULL;
- myrda = NULL;
-
- myproc = (struct Process *)FindTask(NULL);
- if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",36)) == NULL)
- { Alert(AT_Recovery|AG_OpenLib|AO_DOSLib);
- return 100;
- }
-
- if (!(myproc->pr_CLI)) /* If started from WB, exit cleanly */
- { WaitPort(&(myproc->pr_MsgPort));
- wbmsg = (struct WBStartup *)GetMsg(&(myproc->pr_MsgPort));
- cleanexit(20);
- }
- else
- { APTR oldwinptr;
- int error = 0;
- struct DosList *dol;
- struct FileSysStartupMsg *startup;
- struct DosEnvec *dosenv;
- STRPTR fssmdev;
- char buffer[DNAME_SIZE];
- UBYTE *colon;
- BYTE TDretries = 0;
-
- memset((char *)opts, 0, sizeof(opts));
- if ((myrda = ReadArgs(template, opts, NULL)) == NULL)
- { PrintFault(IoErr(),"CheckDisk");
- cleanexit(20);
- }
-
- oldwinptr = myproc->pr_WindowPtr; /* Disable DOS Requesters */
- myproc->pr_WindowPtr = (APTR)(-1L);
-
- dol = LockDosList(LDF_DEVICES | LDF_READ);
- strncpy(buffer, (STRPTR)opts[OPT_DEVICE], sizeof(buffer));
- if (colon = (UBYTE *)strchr(buffer,':')) *colon = (UBYTE)0;
- else buffer[DNAME_SIZE-1] = (UBYTE)0;
- if (dol = FindDosEntry(dol, buffer, LDF_DEVICES))
- { startup = BADDR(((struct DeviceNode *)dol)->dn_Startup);
- if (TypeOfMem(startup) && ((ULONG)startup & 1) == 0)
- { fssmdev = (STRPTR)BADDR(startup->fssm_Device) + 1;
- if (TypeOfMem(fssmdev))
- { strncpy(mydiskdev.dd_DeviceName, fssmdev, DNAME_SIZE - 1);
- mydiskdev.dd_DeviceUnit = startup->fssm_Unit;
- mydiskdev.dd_DeviceFlags = startup->fssm_Flags;
- dosenv = BADDR(startup->fssm_Environ);
- if (TypeOfMem(dosenv) && ((ULONG)dosenv & 1) == 0 && dosenv->de_TableSize >= 11)
- { mydiskdev.dd_SectorSize = dosenv->de_SizeBlock << 2;
- mydiskdev.dd_SectorsPerBlock = dosenv->de_SectorPerBlock;
- mydiskdev.dd_SectorsPerTrack = dosenv->de_BlocksPerTrack;
- mydiskdev.dd_Surfaces = dosenv->de_Surfaces;
- mydiskdev.dd_LowCyl = dosenv->de_LowCyl;
- mydiskdev.dd_HighCyl = dosenv->de_HighCyl;
- mydiskdev.dd_Reserved = dosenv->de_Reserved;
- if (dosenv->de_TableSize >= 12) mydiskdev.dd_BufMemType = dosenv->de_BufMemType;
- else mydiskdev.dd_BufMemType = MEMF_ANY;
- if (dosenv->de_TableSize >= 13) mydiskdev.dd_MaxTransfer = dosenv->de_MaxTransfer;
- else mydiskdev.dd_MaxTransfer = 0x1fe00;
- if (dosenv->de_TableSize >= 16) mydiskdev.dd_DOSType = dosenv->de_DosType;
- else mydiskdev.dd_DOSType = ID_DOS_DISK;
- }
- else error = -1;
- }
- else error = -2;
- }
- else error = -3;
- UnLockDosList(LDF_DEVICES | LDF_READ);
- myproc->pr_WindowPtr = oldwinptr;
- strcat(buffer, ":");
-
- if (error)
- { Printf("CheckDisk: %s is not a disk structured device (%ld)\n",opts[OPT_DEVICE],error);
- cleanexit(20);
- }
-
- if (opts[OPT_LOWCYL])
- { mydiskdev.dd_LowCyl = *(ULONG *)opts[OPT_LOWCYL];
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- if (opts[OPT_HIGHCYL])
- { mydiskdev.dd_HighCyl = *(ULONG *)opts[OPT_HIGHCYL];
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- if (opts[OPT_READWRITE]) mydiskdev.dd_Flags |= DDFF_READWRITE;
- if (opts[OPT_VERBOSE]) mydiskdev.dd_Flags |= DDFF_VERBOSE;
- if (opts[OPT_BUFCYL]) mydiskdev.dd_CylStep = *(ULONG *)opts[OPT_BUFCYL];
- else mydiskdev.dd_CylStep = 1;
-
- if (mydiskdev.dd_Flags & DDFF_VERBOSE)
- { Printf("Device = %.32s\n", mydiskdev.dd_DeviceName);
- Printf("Unit = %ld\n", mydiskdev.dd_DeviceUnit);
- Printf("Flags = %08lx\n", mydiskdev.dd_DeviceFlags);
- Printf("SectorSize = %lu\n", mydiskdev.dd_SectorSize);
- Printf("SectorsPerBlock = %lu\n", mydiskdev.dd_SectorsPerBlock);
- Printf("SectorsPerTrack = %lu\n", mydiskdev.dd_SectorsPerTrack);
- Printf("Surfaces = %lu\n", mydiskdev.dd_Surfaces);
- Printf("LowCyl = %lu\n", mydiskdev.dd_LowCyl);
- Printf("HighCyl = %lu\n", mydiskdev.dd_HighCyl);
- Printf("Reserved = %lu\n", mydiskdev.dd_Reserved);
- Printf("BufMemType = %lu\n", mydiskdev.dd_BufMemType);
- Printf("MaxTransfer = %08lx\n", mydiskdev.dd_MaxTransfer);
- Printf("DosType = %08lx\n", mydiskdev.dd_DOSType);
- }
-
- if (DeviceMP = CreateMsgPort())
- { if (DeviceIO = CreateIORequest(DeviceMP, sizeof(struct IOStdReq)))
- { if ((error = OpenDevice(mydiskdev.dd_DeviceName, mydiskdev.dd_DeviceUnit, (struct IORequest *)DeviceIO, mydiskdev.dd_DeviceFlags)) == 0)
- { BPTR bb_lock=0;
- ULONG *bootblock;
- char inbuf[4];
-
- /* Check if a disk in present and if it is write enabled */
-
- while (checkstate(DeviceIO))
- { PutStr("There's no disk in the drive !\n");
- PutStr("Insert a disk and hit return to continue\n");
- FGets(Input(), inbuf, sizeof(inbuf) - 1);
- Flush(Input());
- PutStr("\n");
- }
-
- if (checkprotection(DeviceIO))
- { PutStr("Disk is write protected !\n");
- PutStr("Bad block mapping is disabled\n\n");
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
-
- /* Check if we need 64bit commands and if they are available */
-
- if (error = initFFS())
- { PrintFault(error, "CheckDisk");
- cleanexit(20);
- }
-
- /* Try to read the boot block, and update the volume DOS ID */
-
- if (!(mydiskdev.dd_Flags & DDFF_CUSTOM))
- { if (bootblock = readblock(0))
- { mydiskdev.dd_DOSType = bootblock[BOOT_ID];
- FreeVec(bootblock);
- }
- else
- { Printf("Warning: Couldn't read volume boot block (error %ld)\n", DeviceIO->io_Error);
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- }
-
- if ((mydiskdev.dd_DOSType & ID_DOS_DISK) != ID_DOS_DISK && mydiskdev.dd_DOSType != ID_MUFS_DISK)
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
-
- /* If we are scanning an AmigaDOS volume, check for an existing badblocks file */
-
- if (!(mydiskdev.dd_Flags & DDFF_CUSTOM) && (bb_lock = openbadblocksfile(buffer)))
- { if (!(BBList = readbadblocks(bb_lock))) PutStr("Warning: Couldn't read existing bad blocks file\n");
- }
-
- if (!opts[OPT_NOINHIBIT])
- { if (Inhibit(buffer, DOSTRUE) == DOSFALSE)
- { Printf("CheckDisk: couldn't inhibit drive %s\n", buffer);
- freebadblocklist(BBList);
- if (bb_lock) UnLock(bb_lock);
- cleanexit(20);
- }
- }
-
- /* If we are scanning an AmigaDOS volume, read root block and bitmap */
-
- if (!(mydiskdev.dd_Flags & DDFF_CUSTOM))
- { if (rootblock = readblock(mydiskdev.dd_RootKey))
- { if (error = checkblock(rootblock, mydiskdev.dd_RootKey, T_SHORT, ST_ROOT))
- { Printf("Warning: Invalid root block (error %ld)\n", error);
- FreeVec(rootblock);
- rootblock = NULL;
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- else
- { if (rootblock[mydiskdev.dd_BlockSizeL+ROOT_BITMAPFLAG])
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("\nReading volume bitmap\n");
- if (!(bitmap = readbitmap(rootblock)))
- { PutStr("Warning: Couldn't read volume bitmap\n");
- FreeVec(rootblock);
- rootblock = NULL;
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- else if (opts[OPT_RESET])
- { freebadblocks(BBList); /* Ignore existing bad blocks, mark them free */
- freebadblocklist(BBList);
- BBList = NULL;
- mydiskdev.dd_Flags |= DDFF_MODIFIED;
- }
- }
- else
- { PutStr("Warning: Volume bitmap is invalid\n");
- FreeVec(rootblock);
- rootblock = NULL;
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- }
- }
- else
- { Printf("Warning: Couldn't read volume root block (error %ld)\n", DeviceIO->io_Error);
- mydiskdev.dd_Flags |= DDFF_CUSTOM;
- }
- }
-
- /* If severe mode requested, disable retries for trackdisk unit */
-
- if (opts[OPT_SEVERE] && !strcmp(mydiskdev.dd_DeviceName, TD_NAME) && DeviceIO->io_Unit)
- { TDretries = ((struct TDU_PublicUnit *)DeviceIO->io_Unit)->tdu_RetryCnt;
- ((struct TDU_PublicUnit *)DeviceIO->io_Unit)->tdu_RetryCnt = 0;
- }
-
- if (error = checkdisk())
- { PrintFault(error, "CheckDisk");
- rc = 10;
- }
-
- if (opts[OPT_SEVERE] && TDretries) ((struct TDU_PublicUnit *)DeviceIO->io_Unit)->tdu_RetryCnt = TDretries;
-
- /* If the bad block list was modified, write the bad blocks file back */
-
- if (!rc && mydiskdev.dd_Flags & DDFF_MODIFIED)
- { writebadblocks(BBList, bb_lock);
- DateStamp((struct DateStamp *)&rootblock[mydiskdev.dd_BlockSizeL+ROOT_VOLUMEDAYS]);
- rootblock[mydiskdev.dd_BlockSizeL+ROOT_BITMAPFLAG] = 0; /* Mark bitmap as dirty */
- sumblock(rootblock);
- if (error = writeblock(rootblock, mydiskdev.dd_RootKey))
- Printf("Error: Couldn't write back volume root block (error %ld)\n", error);
- }
-
- if (BBList) freebadblocklist(BBList);
- if (bitmap) FreeVec(bitmap);
- if (rootblock) FreeVec(rootblock);
-
- if (!opts[OPT_NOINHIBIT]) Inhibit(buffer, DOSFALSE);
-
- if (bb_lock) UnLock(bb_lock);
- CloseDevice((struct IORequest *)DeviceIO);
- DeviceIO->io_Device = NULL;
- }
- else Printf("Unable to open %s unit %ld\n", mydiskdev.dd_DeviceName, mydiskdev.dd_DeviceUnit);
- DeleteIORequest(DeviceIO);
- DeviceIO = NULL;
- }
- else
- { PutStr("Unable to create IORequest\n");
- PrintFault(ERROR_NO_FREE_STORE, "CheckDisk");
- }
- DeleteMsgPort(DeviceMP);
- DeviceMP = NULL;
- }
- else
- { PutStr("Unable to create MsgPort\n");
- PrintFault(ERROR_NO_FREE_STORE, "CheckDisk");
- }
-
- }
- else
- { UnLockDosList(LDF_DEVICES | LDF_READ);
- PrintFault(ERROR_DEVICE_NOT_MOUNTED, "CheckDisk");
- rc = 20;
- }
-
- }
- cleanexit(rc);
- }
-
- static void cleanexit(ULONG rc)
- {
- if (DeviceIO && DeviceIO->io_Device) CloseDevice((struct IORequest *)DeviceIO);
- if (DeviceIO) DeleteIORequest(DeviceIO);
- if (DeviceMP) DeleteMsgPort(DeviceMP);
- if (myrda) FreeArgs(myrda);
- if (DOSBase) CloseLibrary((struct Library *)DOSBase);
- if (wbmsg)
- { Forbid();
- ReplyMsg((struct Message *)wbmsg);
- }
- Exit(rc);
- }
-
- static int checkdisk(void)
- { int error=0, cyl;
- ULONG bufsize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerCyl;
- APTR buffer = NULL;
-
- if (mydiskdev.dd_CylStep > 1)
- { bufsize *= mydiskdev.dd_CylStep;
- if (bufsize > mydiskdev.dd_MaxTransfer || (buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType)) == NULL)
- { bufsize /= mydiskdev.dd_CylStep;
- mydiskdev.dd_CylStep = 1;
- }
- }
- if (!buffer)
- { if (bufsize > mydiskdev.dd_MaxTransfer || (buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType)) == NULL)
- { bufsize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerTrack; /* Else try full tracks */
- if (bufsize > mydiskdev.dd_MaxTransfer || (buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType)) == NULL)
- { bufsize = mydiskdev.dd_SectorSize; /* Finally try single sectors */
- buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType);
- }
- }
- }
-
- if (buffer)
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE)
- { Printf("\nBuffer = %08lx\n", buffer);
- Printf("BufSize = %lu\n", bufsize);
- PutStr("\n");
- }
-
- for (cyl = mydiskdev.dd_LowCyl ; cyl <= mydiskdev.dd_HighCyl ; cyl += mydiskdev.dd_CylStep)
- { checkcyl(DeviceIO, buffer, bufsize, cyl);
- if (CheckSignal(SIGBREAKF_CTRL_C))
- { PutStr("\nAborted !\n");
- error = ERROR_BREAK;
- break;
- }
- }
- PutStr("\n");
-
- FreeMem(buffer, bufsize);
- }
- else
- { Printf("Unable to allocate %lu bytes for data buffer\n", bufsize);
- error = ERROR_NO_FREE_STORE;
- }
-
- return error;
- }
-
- #define io_HighOffset io_Actual
-
- static int checkcyl(struct IOStdReq *ioreq, APTR buffer, ULONG bufsize, int cyl)
- { ULONG cylsize, tracksize, cylsize512, tracksize512;
- int error, head, cyl1;
-
- tracksize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerTrack;
- cylsize = tracksize * mydiskdev.dd_Surfaces;
- cylsize512 = cylsize / 512;
- tracksize512 = tracksize / 512;
- Printf("Checking cylinder %ld\r", cyl);
- Flush(Output());
-
- if (bufsize == cylsize * mydiskdev.dd_CylStep)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = cyl+mydiskdev.dd_CylStep > mydiskdev.dd_HighCyl+1 ? (mydiskdev.dd_HighCyl-cyl+1)*cylsize : bufsize;
- ioreq->io_Offset = cyl * cylsize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_READ64;
- ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_READ;
- if (error = DoIO((struct IORequest *)ioreq))
- { for (cyl1 = cyl ; cyl1 < cyl + mydiskdev.dd_CylStep ; cyl1++)
- { checkbysectors(ioreq, buffer, cylsize, cyl1, 0);
- if (cyl1 == mydiskdev.dd_HighCyl || SetSignal(0,0) & SIGBREAKF_CTRL_C) break;
- }
- }
- if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = cyl+mydiskdev.dd_CylStep > mydiskdev.dd_HighCyl+1 ? (mydiskdev.dd_HighCyl-cyl+1)*cylsize : bufsize;
- ioreq->io_Offset = cyl * cylsize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_WRITE64;
- ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_WRITE;
- if (error = DoIO((struct IORequest *)ioreq))
- { for (cyl1 = cyl ; cyl1 < cyl + mydiskdev.dd_CylStep ; cyl1++)
- { checkbysectors(ioreq, buffer, cylsize, cyl, 0);
- if (cyl1 == mydiskdev.dd_HighCyl || SetSignal(0,0) & SIGBREAKF_CTRL_C) break;
- }
- }
- }
- }
- else if (bufsize == cylsize)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = bufsize;
- ioreq->io_Offset = cyl * cylsize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_READ64;
- ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_READ;
- if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, cylsize, cyl, 0);
- if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = bufsize;
- ioreq->io_Offset = cyl * cylsize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_WRITE64;
- ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_WRITE;
- if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, cylsize, cyl, 0);
- }
- }
- else if (bufsize == tracksize)
- { for (head = 0 ; head < mydiskdev.dd_Surfaces ; head++)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = bufsize;
- ioreq->io_Offset = cyl * cylsize + head * tracksize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_READ64;
- ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512) / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_READ;
- if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, tracksize, cyl, head);
- if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = bufsize;
- ioreq->io_Offset = cyl * cylsize + head * tracksize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_WRITE64;
- ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512) / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_WRITE;
- if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, tracksize, cyl, head);
- }
- }
- }
- else error = checkbysectors(ioreq, buffer, cylsize, cyl, 0);
-
- return error;
- }
-
- static int checkbysectors(struct IOStdReq *ioreq, APTR buffer, ULONG size, int cyl, int starthead)
- { ULONG cylsize, tracksize, cylsize512, tracksize512, sectorsize512;
- int error, head, sector, endhead;
-
- tracksize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerTrack;
- cylsize = tracksize * mydiskdev.dd_Surfaces;
- cylsize512 = cylsize / 512;
- tracksize512 = tracksize / 512;
- sectorsize512 = mydiskdev.dd_SectorSize / 512;
- if (size == tracksize) endhead = starthead + 1;
- else endhead = mydiskdev.dd_Surfaces;
-
- if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("\n");
- for (head = starthead ; head < endhead ; head++)
- { for (sector = 0 ; sector < mydiskdev.dd_SectorsPerTrack ; sector++)
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("Checking cylinder %ld, head %ld, sector %ld \r", cyl, head, sector);
- ioreq->io_Data = buffer;
- ioreq->io_Length = mydiskdev.dd_SectorSize;
- ioreq->io_Offset = cyl * cylsize + head * tracksize + sector * mydiskdev.dd_SectorSize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_READ64;
- ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512 + sector * sectorsize512) / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_READ;
- if (error = DoIO((struct IORequest *)ioreq))
- { Printf("Read error %ld on cylinder %ld head %ld sector %ld\n", error, cyl, head, sector);
- if (!(mydiskdev.dd_Flags & DDFF_CUSTOM)) mapbadblock(cyl, head, sector);
- }
- if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
- { ioreq->io_Data = buffer;
- ioreq->io_Length = mydiskdev.dd_SectorSize;
- ioreq->io_Offset = cyl * cylsize + head * tracksize + sector * mydiskdev.dd_SectorSize;
- if (mydiskdev.dd_Flags & DDFF_DO64BIT)
- { ioreq->io_Command = NSCMD_TD_WRITE64;
- ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512 + sector * sectorsize512) / (8*1024*1024);
- }
- else ioreq->io_Command = CMD_WRITE;
- if (error = DoIO((struct IORequest *)ioreq))
- { Printf("Write error %ld on cylinder %ld head %ld sector %ld\n", error, cyl, head, sector);
- if (!(mydiskdev.dd_Flags & DDFF_CUSTOM)) mapbadblock(cyl, head, sector);
- }
- }
- }
- }
-
- if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("\n");
- return error;
- }
-
- static BPTR openbadblocksfile(STRPTR device)
- { char buffer[DNAME_SIZE];
- BPTR lock=0;
- int i;
-
- for (i = 0 ; i < NUMBBNAMES ; i++)
- { strcpy(buffer, device);
- if (AddPart(buffer, BadBlockFileNames[i], DNAME_SIZE))
- { if (lock = Lock(buffer, ACCESS_READ))
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("\nFound existing %s file\n", BadBlockFileNames[i]);
- break;
- }
- }
- }
-
- return lock;
- }
-
- /* Read existing bad blocks file into memory (struct BadBlockList) */
-
- static struct BadBlockList *readbadblocks(BPTR bbflock)
- { ULONG bblkey = ((struct FileLock *)BADDR(bbflock))->fl_Key, badkey;
- ULONG *header;
- struct BadBlockList *bbl = NULL, *bbl1, *bblc;
- int type=T_SHORT, error, numblocks, totblocks=0, blkinlist=0, i;
-
- do
- { if (header = readblock(bblkey))
- { if (error = checkblock(header, bblkey, type, ST_FILE))
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: error %ld\n", error);
- FreeVec(header);
- freebadblocklist(bbl);
- return NULL;
- }
- if (numblocks = header[FILE_BLOCKCOUNT])
- { for (i = 0 ; i < numblocks ; i++)
- { if (!bbl) if (!(bblc = bbl = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR))) return NULL;
- if ((badkey = header[mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1-i]) < mydiskdev.dd_Reserved || badkey > mydiskdev.dd_HighKey)
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: invalid bad block number %lu\n", badkey);
- continue;
- }
- if (blkinlist == BBL_SIZE)
- { if (!(bbl1 = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR)))
- { freebadblocklist(bbl);
- FreeVec(header);
- return NULL;
- }
- bblc->bbl_Link = bbl1;
- bblc = bbl1;
- blkinlist = 0;
- }
- bblc->bbl_BadBlocks[blkinlist++] = badkey;
- totblocks++;
- }
- }
- bblkey = header[mydiskdev.dd_BlockSizeL+FILE_EXTENSION];
- type = T_LIST;
- FreeVec(header);
- }
- else
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: error %ld\n", DeviceIO->io_Error);
- break;
- }
- } while (bblkey);
-
- if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: total of %ld existing bad blocks\n", totblocks);
- return bbl;
- }
-
- /* Write bad block list in memory back into a bad blocks file on disk */
-
- static int writebadblocks(struct BadBlockList *bbl, BPTR bbflock)
- { ULONG bblkey, extkey, chainkey;
- ULONG *headerblock, *extblock=NULL, *fileblock;
- UWORD blocksize = mydiskdev.dd_DOSType & 0x1 ? 4*mydiskdev.dd_BlockSizeL : 4*(mydiskdev.dd_BlockSizeL-DATA_DATABYTES);
- int error, bblk, blkptr, totblocks=0;
-
- if (bbflock)
- { bblkey = ((struct FileLock *)BADDR(bbflock))->fl_Key;
- if (headerblock = readblock(bblkey))
- { if (error = checkblock(headerblock, bblkey, T_SHORT, ST_FILE))
- { Printf("writebadblocks: Invalid header block (error %ld)\n", error);
- FreeVec(headerblock);
- return error;
- }
- else clearblockptrs(headerblock);
- }
- else
- { Printf("writebadblocks: Couldn't read header block (error %ld)\n", DeviceIO->io_Error);
- return DeviceIO->io_Error;
- }
- }
- else
- { if (bblkey = getfreeblock(bitmap))
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("writebadblocks: Allocated key %lu for file header\n", bblkey);
- if (!(headerblock = initheader(bblkey, mydiskdev.dd_RootKey, T_SHORT, ST_FILE, BadBlockFileNames[0])))
- { PutStr("writebadblocks: No memory for fileheader\n");
- return ERROR_NO_FREE_STORE;
- }
- if (muBase = (struct muBase *)OpenLibrary(MULTIUSERNAME, 39))
- { headerblock[mydiskdev.dd_BlockSizeL+FILE_OWNER] = muGetTaskOwner(NULL);
- CloseLibrary((struct Library *)muBase);
- muBase = NULL;
- }
- }
- else
- { PutStr("writebadblocks: Volume is full\n");
- return ERROR_DISK_FULL;
- }
- }
-
- blkptr = mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1;
-
- if (bbl)
- { if (headerblock[FILE_FIRSTBLOCK] = bbl->bbl_BadBlocks[0])
- { fileblock = headerblock;
- do
- { for (bblk = 0 ; bblk < BBL_SIZE ; bblk++)
- { fileblock[blkptr--] = bbl->bbl_BadBlocks[bblk];
- fileblock[FILE_BLOCKCOUNT]++;
- totblocks++;
-
- if (bblk + 1 < BBL_SIZE)
- if (bbl->bbl_BadBlocks[bblk+1] == 0) break;
-
- if (blkptr < FILE_DATABLOCKS)
- { if (extkey = fileblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION])
- { if (extblock = readblock(extkey))
- { if (error = checkblock(extblock, extkey, T_LIST, ST_FILE))
- { Printf("writebadblocks: Invalid extension block (error %ld)\n", error);
- FreeVec(extblock);
- FreeVec(headerblock);
- return error;
- }
- else clearblockptrs(extblock);
- }
- else
- { Printf("writebadblocks: Couldn't read extension block (error %ld)\n", DeviceIO->io_Error);
- FreeVec(headerblock);
- return DeviceIO->io_Error;
- }
- }
- else if (extkey = getfreeblock(bitmap))
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("writebadblocks: Allocated key %lu for extension block\n", extkey);
- if (!(extblock = initheader(extkey, bblkey, T_LIST, ST_FILE, "")))
- { PutStr("writebadblocks: No memory for file extension block\n");
- FreeVec(headerblock);
- return ERROR_NO_FREE_STORE;
- }
- fileblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = extkey;
- }
- else
- { PutStr("writebadblocks: Volume is full\n");
- if (extblock) FreeVec(extblock);
- FreeVec(headerblock);
- return ERROR_DISK_FULL;
- }
-
- if (fileblock != headerblock)
- { sumblock(fileblock);
- if (error = writeblock(fileblock, fileblock[FEXT_OWNKEY]))
- { Printf("writebadblocks: Couldn't write extension block (error %ld)\n", error);
- FreeVec(extblock);
- FreeVec(fileblock);
- return error;
- }
- else FreeVec(fileblock);
- }
- fileblock = extblock;
- extblock = NULL;
- blkptr = mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1;
- }
- }
- } while (bbl = bbl->bbl_Link);
-
- /* write back last extension block */
-
- if (fileblock != headerblock)
- { fileblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
- sumblock(fileblock);
- if (error = writeblock(fileblock, fileblock[FEXT_OWNKEY]))
- { Printf("writebadblocks: Couldn't write extension block (error %ld)\n", error);
- FreeVec(fileblock);
- return error;
- }
- else FreeVec(fileblock);
- }
- else headerblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
- }
- else headerblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
- }
- else headerblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
-
- /* write back file header */
-
- headerblock[mydiskdev.dd_BlockSizeL+FILE_PROTECTION] = FIBF_HOLD | FIBF_ARCHIVE | FIBF_OTR_EXECUTE |
- FIBF_GRP_EXECUTE | FIBF_READ | FIBF_WRITE | FIBF_DELETE;
- headerblock[mydiskdev.dd_BlockSizeL+FILE_BYTESIZE] = totblocks * blocksize;
- DateStamp((struct DateStamp *)&headerblock[mydiskdev.dd_BlockSizeL+FILE_DAYS]);
-
- if (!bbflock)
- { if ((chainkey = gethashchain(rootblock, headerblock)) == (ULONG)(-1L))
- { PutStr("writebadblocks: Couldn't get chain pointer\n");
- FreeVec(headerblock);
- return -1;
- }
- headerblock[mydiskdev.dd_BlockSizeL+FILE_HASHCHAIN] = chainkey;
- sumblock(headerblock);
- if (error = writeblock(headerblock, bblkey))
- { Printf("writebadblocks: Couldn't write file header block (error %ld)\n", error);
- FreeVec(headerblock);
- return error;
- }
- if (error = hashlink(rootblock, headerblock))
- { Printf("writebadblocks: Couldn't link file header to directory (error %ld)\n", error);
- FreeVec(headerblock);
- return error;
- }
- }
- else
- { sumblock(headerblock);
- if (error = writeblock(headerblock, bblkey))
- { Printf("writebadblocks: Couldn't write file header block (error %ld)\n", error);
- FreeVec(headerblock);
- return error;
- }
- }
-
- FreeVec(headerblock);
- if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("writebadblocks: total of %ld bad blocks mapped out\n", totblocks);
- return 0;
- }
-
- static ULONG getfreeblock(ULONG *bitmap)
- { ULONG block=0, goodblock=0;
-
- do
- { if (block = findfreeblock(bitmap, block))
- { if (checkbadblock(block)) continue;
- else
- { allocblock(bitmap, block);
- goodblock = block;
- break;
- }
- }
- } while (block);
-
- return goodblock;
- }
-
- static void freebadblocklist(struct BadBlockList *bbl)
- { struct BadBlockList *bblc=bbl, *nextbbl;
-
- while (bblc)
- { nextbbl = bblc->bbl_Link;
- FreeMem(bblc, sizeof(struct BadBlockList));
- bblc = nextbbl;
- }
- }
-
- static BOOL checkbadblock(ULONG KeyID)
- { struct BadBlockList *bblc;
- int i;
-
- for (bblc = BBList ; bblc ; bblc = bblc->bbl_Link)
- for (i = 0 ; i < BBL_SIZE ; i++)
- { if (bblc->bbl_BadBlocks[i] == KeyID) return TRUE;
- if (bblc->bbl_BadBlocks[i] == 0) return FALSE;
- }
-
- return FALSE;
- }
-
- static void mapbadblock(ULONG badcyl, ULONG badhead, ULONG badsector)
- { ULONG lowsec = mydiskdev.dd_LowCyl * mydiskdev.dd_SectorsPerCyl;
- ULONG badsec, badkey, lowbadsec, highbadsec, lowbadkey, highbadkey;
-
- badsec = badcyl*mydiskdev.dd_SectorsPerCyl + badhead*mydiskdev.dd_SectorsPerTrack + badsector;
- badkey = (badsec - lowsec) / mydiskdev.dd_SectorsPerBlock;
- if (checkbadblock(badkey)) Printf("old bad block found (sector %lu, key %lu)\n", badsec, badkey);
- else
- { Printf("new bad block found (sector %lu, key %lu)\n", badsec, badkey);
- mydiskdev.dd_Flags |= DDFF_MODIFIED;
- if (!strcmp(mydiskdev.dd_DeviceName, TD_NAME))
- { lowbadsec = badcyl*mydiskdev.dd_SectorsPerCyl + badhead*mydiskdev.dd_SectorsPerTrack;
- highbadsec = lowbadsec + mydiskdev.dd_SectorsPerTrack - 1;
- lowbadkey = (lowbadsec - lowsec) / mydiskdev.dd_SectorsPerBlock;
- highbadkey = (highbadsec - lowsec) / mydiskdev.dd_SectorsPerBlock;
- if (lowbadkey < mydiskdev.dd_Reserved) lowbadkey = mydiskdev.dd_Reserved;
- for (badkey = lowbadkey ; badkey <= highbadkey ; badkey++)
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("adding bad key %lu\n", badkey);
- if (!addbadblock(badkey)) PutStr("Warning: failed to add bad block\n\n");
- }
- }
- else
- { if (badkey >= mydiskdev.dd_Reserved)
- { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("adding bad key %lu\n", badkey);
- if (!addbadblock(badkey)) PutStr("Warning: failed to add bad block\n\n");
- }
- }
- }
- PutStr("\n");
- }
-
- static BOOL addbadblock(ULONG KeyID)
- { struct BadBlockList *bblc;
- int i;
-
- if (!BBList) if (!(BBList = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR))) return FALSE;
-
- for (bblc = BBList ; bblc ; bblc = bblc->bbl_Link)
- { for (i = 0 ; i < BBL_SIZE ; i++)
- { if (bblc->bbl_BadBlocks[i] == KeyID) return TRUE;
- if (bblc->bbl_BadBlocks[i] == 0)
- { if (allocblock(bitmap, KeyID))
- { bblc->bbl_BadBlocks[i] = KeyID;
- return TRUE;
- }
- else
- { Printf("Key %lu already marked in use in bitmap\n", KeyID);
- return FALSE;
- }
- }
- }
- if (!bblc->bbl_Link) if (!(bblc->bbl_Link = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR))) return FALSE;
- }
-
- return FALSE;
- }
-
- static void freebadblocks(struct BadBlockList *bbl)
- { struct BadBlockList *bblc=bbl;
- ULONG key;
- int i;
-
- while (bblc)
- { for (i = 0 ; i < BBL_SIZE ; i++)
- { if (key = bblc->bbl_BadBlocks[i]) freeblock(bitmap, key);
- else break;
- }
- bblc = bblc->bbl_Link;
- }
- }
-
- static __inline BOOL checkprotection(struct IOStdReq *ioreq)
- { ioreq->io_Command = TD_PROTSTATUS;
- if (!DoIO((struct IORequest *)ioreq)) return (BOOL)ioreq->io_Actual;
- else return TRUE;
- }
-
- static __inline BOOL checkstate(struct IOStdReq *ioreq)
- { ioreq->io_Command = TD_CHANGESTATE;
- if (!DoIO((struct IORequest *)ioreq)) return (BOOL)ioreq->io_Actual;
- else return TRUE;
- }
-